package com.molichuxing.gateway.api.aspect;

import java.time.LocalDateTime;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.utils.Md5Util;
import com.molichuxing.framework.utils.RedisUtil;
import com.molichuxing.framework.utils.StringUtil;
import com.molichuxing.gateway.utils.RedisPermissionUtil;
import com.molichuxing.services.infrastructure.service.ResourceService;
import com.molichuxing.services.property.GroupSystemTypeEnum;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.molichuxing.framework.dto.RequestRootDto;
import com.molichuxing.framework.property.OperatorTypeEnum;
import com.molichuxing.framework.result.ResponseCodeEnum;
import com.molichuxing.framework.result.ResponseResult;
import com.molichuxing.gateway.utils.TokenUtil;
import com.molichuxing.gateway.utils.contants.RequestAttrConst;
import com.molichuxing.gateway.utils.entity.UserEntity;

/**
 * 登录过滤
 * 
 * @author zoumingyu
 * @date 2019年8月8日
 *
 */
@Aspect
@Order(1)
public class TokenAspect {
	private final static Logger logger = LoggerFactory.getLogger("[dealer-gateway登录过滤]");

	@Resource
	private TokenUtil tokenUtil;

	private List<String> excludeMapping;

	@Resource
	private RedisUtil redisUtil;

	@Resource
	private RedisPermissionUtil redisPermissionUtil;

	@Resource
	private ResourceService resourceService;

	// 环境
	@Value("${profiles.active}")
	private String active;

    private List<String> permissionExcludeMapping;

    public void setPermissionExcludeMapping(List<String> permissionExcludeMapping) {
        this.permissionExcludeMapping = permissionExcludeMapping;
    }

    public void setExcludeMapping(List<String> excludeMapping) {
		this.excludeMapping = excludeMapping;
	}

	@Pointcut("execution(public * com.molichuxing.gateway.api.services.impl..*(..))")
	public void token() {
	}

	@Around("token()")
	public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		HttpServletResponse response = attributes.getResponse();
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "*");
		response.setHeader("Access-Control-Allow-Headers",
				"Origin,Content-Type,Accept,channel,token,workertoken,bondtoken,X-Requested-With");
		response.setHeader("Access-Control-Allow-Credentials", "true");
		// 忽略OPTIONS预校验请求
		if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
			return joinPoint.proceed();
		}

		String uri = request.getRequestURI();
		// 放过不拦截接口
		for (String exclude : excludeMapping) {
			if (uri.equalsIgnoreCase(exclude)) {
				return joinPoint.proceed();
			}
		}
		// 用户token
		String token = request.getHeader("token");
		if (StringUtils.isBlank(token)) {
			return noLogin();
		}
		// 根据token从redis中获取操作人相关信息
		UserEntity user = tokenUtil.getUser(token);
		if (user == null) {
			return noLogin();
		}

		// 查询用户相关经销商，并存入request
		request.setAttribute(RequestAttrConst.DEALER_KEY, user.getDealer());

		//判断ssotoken是否一致，不一致，那么没有权限
		if (!user.getSsoToken().equals(token)) {
			return pushOut();
		}
		tokenUtil.expire(token);

        //权限认证
        if (!user.getIsSuper()) { //超级管理员不验证权限，非超级管理员验证权限
            for (String exclude : permissionExcludeMapping) {
                if (uri.equalsIgnoreCase(exclude)) {
                    return joinPoint.proceed();
                } else if (exclude.endsWith("/*")) {
                    exclude = exclude.substring(0, exclude.length() - 2);
                    if (uri.startsWith(exclude)) {
                        return joinPoint.proceed();
                    }
                }
            }

            if (user.getGroupId() != null && user.getGroupId() > 0) {
                String key =  RedisKeyConst.DEALER_GROUP_PERMISSION + Md5Util.md5Hex(active) +"."+  Md5Util.md5Hex(user.getGroupId()+"");
				boolean exists = redisUtil.exists(key); //检查key是否存，如不存在，则set一遍
				if (!exists) {
					redisPermissionUtil.resourceToRedis(user.getGroupId());
				}
                String value = redisUtil.hget(key, uri);;
                if (StringUtil.isEmpty(value))
                    return noPermission();
            } else {
                return noPermission();
            }
        }
        //权限认证end


		Object[] objArray = joinPoint.getArgs();
		for (Object obj : objArray) {
			if (obj != null && obj instanceof RequestRootDto) {
				RequestRootDto dto = (RequestRootDto) obj;
				// 赋值操作人相关信息
				dto.setOperateId(user.getAccountId()); // 操作人id
				dto.setOperateName(user.getRealName()); // 操作人姓名
				dto.setOperateDate(LocalDateTime.now()); // 操作时间
				dto.setOperatorType(OperatorTypeEnum.DEALER); // 操作人员类型-经销商
			}
		}

		return joinPoint.proceed();
	}

	private ResponseResult<String> noLogin() {
		return new ResponseResult<String>().error(ResponseCodeEnum.LOGIN_ERROR);
	}

	private ResponseResult<String> pushOut() {
		return new ResponseResult<String>().error(ResponseCodeEnum.LOGIN_ERROR.getCode(), "您的帐号在另一地点登录，您被迫下线");
	}

	private ResponseResult<String> noPermission() {
		return new ResponseResult<String>().error(ResponseCodeEnum.NO_PERMISSION);
	}
}
